/*
 * Copyright (C) 2021 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.facebook.fresco.helper;

import ohos.agp.components.ComponentContainer;
import ohos.app.Context;
import ohos.app.dispatcher.TaskDispatcher;
import ohos.media.image.ImageSource;
import ohos.media.image.PixelMap;
import ohos.media.image.common.PixelFormat;
import ohos.media.image.common.Rect;
import ohos.media.image.common.Size;
import ohos.utils.net.Uri;

import com.facebook.common.util.UriUtil;
import com.facebook.drawee.backends.pipeline.Fresco;
import com.facebook.drawee.controller.ControllerListener;
import com.facebook.drawee.view.SimpleDraweeView;
import com.facebook.fresco.helper.config.PhoenixConfig;
import com.facebook.fresco.helper.listener.IDownloadResult;
import com.facebook.fresco.helper.listener.IResult;
import com.facebook.fresco.helper.photoview.LargePhotoView;
import com.facebook.fresco.helper.utils.CircleBitmapTransform;
import com.facebook.fresco.helper.utils.ImageFileUtils;
import com.facebook.fresco.helper.utils.MLog;
import com.facebook.imagepipeline.core.ImagePipeline;
import com.facebook.imagepipeline.core.ImagePipelineConfig;
import com.facebook.imagepipeline.image.ImageInfo;
import com.facebook.imagepipeline.request.BasePostprocessor;
import com.facebook.imagepipeline.request.ImageRequest;
import com.facebook.imagepipeline.request.ImageRequestBuilder;
import com.oszc.bbhmlibrary.wrapper.TextUtils;

import java.io.File;

/**
 * 凤凰城
 *
 * @author dev
 * @since 2021-07-29
 */
public class Phoenix {
    private Phoenix() {
    }

    /**
     * 初始化
     *
     * @param context 上下文
     */
    public static void init(Context context) {
        init(context, PhoenixConfig.get(context));
    }

    /**
     * 初始化
     *
     * @param context 上下文
     * @param imagePipelineConfig 图像管道配置
     */
    public static void init(Context context, ImagePipelineConfig imagePipelineConfig) {
        Fresco.initialize(context, imagePipelineConfig);
    }

    /**
     * 与
     *
     * @param simpleDraweeView 简单的付款人视图
     * @return {@link Builder}
     */
    public static Builder with(SimpleDraweeView simpleDraweeView) {
        return new Builder().build(simpleDraweeView);
    }

    /**
     * 与
     *
     * @param subsamplingScaleImageView 二次抽样规模图像视图
     * @return {@link Builder}
     */
    public static Builder with(LargePhotoView subsamplingScaleImageView) {
        return new Builder().build(subsamplingScaleImageView);
    }

    /**
     * 与
     *
     * @param context 上下文
     * @return {@link Builder}
     */
    public static Builder with(Context context) {
        return new Builder().build(context);
    }

    /**
     * 与
     *
     * @param url url
     * @return {@link Builder}
     */
    public static Builder with(String url) {
        return new Builder().build(url);
    }

    /**
     * 与
     *
     * @return {@link Builder}
     */
    public static Builder with() {
        return new Builder();
    }

    /**
     * 驱逐从内存缓存
     *
     * @param uri uri
     */
    public static void evictFromMemoryCache(final Uri uri) {
        ImagePipeline imagePipeline = Fresco.getImagePipeline();
        if (imagePipeline.isInBitmapMemoryCache(uri)) {
            imagePipeline.evictFromMemoryCache(uri);
        }
    }

    /**
     * 驱逐从磁盘缓存
     *
     * @param uri uri
     */
    public static void evictFromDiskCache(final Uri uri) {
        ImagePipeline imagePipeline = Fresco.getImagePipeline();
        if (imagePipeline.isInDiskCacheSync(uri)) {
            imagePipeline.evictFromDiskCache(uri);
        }
    }

    /**
     * 驱逐从磁盘缓存
     *
     * @param url url
     */
    public static void evictFromDiskCache(final String url) {
        evictFromDiskCache(imageUri(url));
    }

    /**
     * 驱逐从缓存
     *
     * @param uri uri
     */
    public static void evictFromCache(final Uri uri) {
        evictFromMemoryCache(uri);
        evictFromDiskCache(uri);
    }

    /**
     * 驱逐从内存缓存
     *
     * @param url url
     */
    public static void evictFromMemoryCache(final String url) {
        evictFromMemoryCache(imageUri(url));
    }

    /**
     * 驱逐从缓存
     *
     * @param url url
     */
    public static void evictFromCache(final String url) {
        evictFromCache(imageUri(url));
    }

    /**
     * 图像uri
     *
     * @param url url
     * @return {@link Uri}
     */
    public static Uri imageUri(String url) {
        Uri uri = Uri.parse(url);
        if (!UriUtil.isNetworkUri(uri)) {
            uri = new Uri.Builder().scheme(UriUtil.LOCAL_FILE_SCHEME).decodedPath(url).build();
        }
        return uri;
    }

    /**
     * 清除内存缓存
     */
    public static void clearMemoryCaches() {
        Fresco.getImagePipeline().clearMemoryCaches();
    }

    /**
     * 明确磁盘缓存
     */
    public static void clearDiskCaches() {
        Fresco.getImagePipeline().clearDiskCaches();
    }

    /**
     * 清除缓存
     */
    public static void clearCaches() {
        clearMemoryCaches();
        clearDiskCaches();
    }

    /**
     * 位图内存缓存
     *
     * @param uri uri
     * @return boolean
     */
    public static boolean isInBitmapMemoryCache(final Uri uri) {
        return Fresco.getImagePipeline().isInBitmapMemoryCache(uri);
    }

    /**
     * 在磁盘高速缓存同步
     *
     * @param uri uri
     * @return boolean
     */
    public static boolean isInDiskCacheSync(final Uri uri) {
        return isInDiskCacheSync(uri, ImageRequest.CacheChoice.SMALL)
            || isInDiskCacheSync(uri, ImageRequest.CacheChoice.DEFAULT);
    }

    /**
     * 在磁盘高速缓存同步
     *
     * @param uri uri
     * @param cacheChoice 缓存的选择
     * @return boolean
     */
    public static boolean isInDiskCacheSync(Uri uri, ImageRequest.CacheChoice cacheChoice) {
        return Fresco.getImagePipeline().isInDiskCacheSync(uri, cacheChoice);
    }

    /**
     * 需要暂停网络请求时调用
     */
    public static void pause() {
        Fresco.getImagePipeline().pause();
    }

    /**
     * 需要恢复网络请求时调用
     */
    public static void resume() {
        Fresco.getImagePipeline().resume();
    }

    /**
     * 当前网络请求是否处于暂停状态
     *
     * @return boolean
     */
    public static boolean isPaused() {
        return Fresco.getImagePipeline().isPaused();
    }

    /**
     * 预加载到内存缓存并解码
     *
     * @param url url
     */
    public static void prefetchToBitmapCache(String url) {
        if (TextUtils.isEmpty(url)) {
            return;
        }

        ImageRequest imageRequest = ImageRequestBuilder.newBuilderWithSource(Uri.parse(url)).build();
        Fresco.getImagePipeline().prefetchToBitmapCache(imageRequest, null);
    }

    /**
     * 预加载到磁盘缓存（未解码）
     *
     * @param url url
     */
    public static void prefetchToDiskCache(String url) {
        if (TextUtils.isEmpty(url)) {
            return;
        }

        ImageRequest imageRequest = ImageRequestBuilder.newBuilderWithSource(Uri.parse(url)).build();
        Fresco.getImagePipeline().prefetchToDiskCache(imageRequest, null);
    }

    /**
     * 获取磁盘上主缓存文件缓存的大小
     *
     * @return long
     */
    public static long getMainDiskStorageCacheSize() {
        Fresco.getImagePipelineFactory().getMainFileCache().trimToMinimum();
        return Fresco.getImagePipelineFactory().getMainFileCache().getSize();
    }

    /**
     * 获取磁盘上副缓存（小文件）文件缓存的大小
     *
     * @return long
     */
    public static long getSmallDiskStorageCacheSize() {
        Fresco.getImagePipelineFactory().getSmallImageFileCache().trimToMinimum();
        return Fresco.getImagePipelineFactory().getSmallImageFileCache().getSize();
    }

    /**
     * 获取磁盘上缓存文件的大小
     *
     * @return long
     */
    public static long getDiskStorageCacheSize() {
        return getMainDiskStorageCacheSize() + getSmallDiskStorageCacheSize();
    }

    /**
     * 构建器
     *
     * @author dev
     * @since 2021-08-03
     */
    public static class Builder {
        private Context mContext;
        private SimpleDraweeView mSimpleDraweeView;
        private LargePhotoView mSubsamplingScaleImageView;

        private String mUrl;
        private String mDiskCachePath; // 超大图的本地缓存目录

        private int mWidth;
        private int mHeight;
        private float mAspectRatio;

        private boolean mNeedBlur;
        private boolean mSmallDiskCache;
        private boolean mCircleBitmap;
        private boolean mFromAssets;

        private BasePostprocessor mPostprocessor;
        private ControllerListener<ImageInfo> mControllerListener;

        private IResult<PixelMap> mResult;
        private IDownloadResult mDownloadResult;

        /**
         * 构建
         *
         * @param url url
         * @return {@link Builder}
         */
        public Builder build(String url) {
            this.mUrl = url;
            return this;
        }

        /**
         * 构建
         *
         * @param context 上下文
         * @return {@link Builder}
         */
        public Builder build(Context context) {
            this.mContext = context.getApplicationContext();
            return this;
        }

        /**
         * 构建
         *
         * @param simpleDraweeView 简单的付款人视图
         * @return {@link Builder}
         */
        public Builder build(SimpleDraweeView simpleDraweeView) {
            this.mSimpleDraweeView = simpleDraweeView;
            return this;
        }

        /**
         * 构建
         *
         * @param subsamplingScaleImageView 二次抽样规模图像视图
         * @return {@link Builder}
         */
        public Builder build(LargePhotoView subsamplingScaleImageView) {
            this.mSubsamplingScaleImageView = subsamplingScaleImageView;
            return this;
        }

        /**
         * 设置网址
         *
         * @param url url
         * @return {@link Builder}
         */
        public Builder setUrl(String url) {
            this.mUrl = url;
            return this;
        }

        /**
         * 设置磁盘高速缓存dir
         *
         * @param diskCacheDir 磁盘高速缓存dir
         * @return {@link Builder}
         */
        public Builder setDiskCacheDir(String diskCacheDir) {
            this.mDiskCachePath = diskCacheDir;
            return this;
        }

        /**
         * 设置宽度
         *
         * @param reqWidth 要求的宽度
         * @return {@link Builder}
         */
        public Builder setWidth(int reqWidth) {
            this.mWidth = reqWidth;
            return this;
        }

        /**
         * 设置高度
         *
         * @param reqHeight 要求的高度
         * @return {@link Builder}
         */
        public Builder setHeight(int reqHeight) {
            this.mHeight = reqHeight;
            return this;
        }

        /**
         * 设置长宽比
         *
         * @param aspectRatio 纵横比
         * @return {@link Builder}
         */
        public Builder setAspectRatio(float aspectRatio) {
            this.mAspectRatio = aspectRatio;
            return this;
        }

        /**
         * 设置需要模糊
         *
         * @param needBlur 需要模糊
         * @return {@link Builder}
         */
        public Builder setNeedBlur(boolean needBlur) {
            this.mNeedBlur = needBlur;
            return this;
        }

        /**
         * 组资产
         *
         * @param fromAssets 从资产
         * @return {@link Builder}
         */
        public Builder setAssets(boolean fromAssets) {
            this.mFromAssets = fromAssets;
            return this;
        }

        /**
         * 设立小磁盘高速缓存
         *
         * @param smallDiskCache 小磁盘高速缓存
         * @return {@link Builder}
         */
        public Builder setSmallDiskCache(boolean smallDiskCache) {
            this.mSmallDiskCache = smallDiskCache;
            return this;
        }

        /**
         * 集圈位图
         *
         * @param circleBitmap 圆图
         * @return {@link Builder}
         */
        public Builder setCircleBitmap(boolean circleBitmap) {
            this.mCircleBitmap = circleBitmap;
            return this;
        }

        /**
         * 组结果
         *
         * @param result 结果
         * @return {@link Builder}
         */
        public Builder setResult(IResult<PixelMap> result) {
            this.mResult = result;
            return this;
        }

        /**
         * 组结果
         *
         * @param result 结果
         * @return {@link Builder}
         */
        public Builder setResult(IDownloadResult result) {
            this.mDownloadResult = result;
            return this;
        }

        /**
         * 集基地后处理程序
         *
         * @param postprocessor 后处理程序
         * @return {@link Builder}
         */
        public Builder setBasePostprocessor(BasePostprocessor postprocessor) {
            this.mPostprocessor = postprocessor;
            return this;
        }

        /**
         * 控制器设置监听器
         *
         * @param controllerListener 控制器监听器
         * @return {@link Builder}
         */
        public Builder setControllerListener(ControllerListener<ImageInfo> controllerListener) {
            this.mControllerListener = controllerListener;
            return this;
        }

        /**
         * 下载
         */
        public void download() {
            if (TextUtils.isEmpty(mUrl) || mDownloadResult == null) {
                return;
            }

            if (UriUtil.isNetworkUri(Uri.parse(mUrl))) {
                ImageLoader.downloadImage(mContext, mUrl, mDownloadResult);
            } else {
                mDownloadResult.onResult("mUrl:" + mUrl);
            }
        }

        /**
         * 负载
         */
        public void load() { // 目前只对从网络加载图片，提供支持
            ImageLoader.loadImage(mContext, mUrl, mWidth, mHeight, new IResult<PixelMap>() {
                @Override
                public void onResult(PixelMap bitmap) {
                    loadImage(bitmap);
                }

                @Override
                public void onProgress(int progress) {
                    if (mResult!=null) {
                        mResult.onProgress(progress);
                    }
                }
            });
        }

        /**
         * 负载
         *
         * @param url url
         */
        public void load(String url) {
            if (TextUtils.isEmpty(url)) {
                return;
            }
            if (!mNeedBlur) {
                loadNormal(url);
            } else {
                loadBlur(url);
            }
        }

        /**
         * 负载
         *
         * @param resId res id
         */
        public void load(int resId) {
            if (resId == 0 || mSimpleDraweeView == null) {
                return;
            }
            adjustLayoutParams();
            if (!mNeedBlur) {
                ImageLoader.loadDrawable(mSimpleDraweeView, resId, mWidth, mHeight);
            } else {
                ImageLoader.loadDrawableBlur(mSimpleDraweeView, resId, mWidth, mHeight);
            }
        }

        private void loadImage(PixelMap bitmap) {
            if (mResult != null) {
                if (mCircleBitmap) {
                    mResult.onResult(CircleBitmapTransform.transform(bitmap));
                } else {
                    mResult.onResult(bitmap);
                }
            }
        }

        /**
         * 加载本地磁盘缓存
         */
        public void loadLocalDiskCache() {
            ImageLoader.loadLocalDiskCache(mContext, mUrl, mResult);
        }

        private void loadNormal(final String url) {
            adjustLayoutParams();
            Uri uri = Uri.parse(url);
            if (!UriUtil.isNetworkUri(uri)) {
                if (mFromAssets) {
                    uri = new Uri.Builder().scheme(UriUtil.LOCAL_ASSET_SCHEME).decodedPath(url).build();
                } else {
                    uri = new Uri.Builder().scheme(UriUtil.LOCAL_FILE_SCHEME).decodedPath(url).build();
                }
            }
            if (mSubsamplingScaleImageView != null) {
                if (mDiskCachePath == null) {
                    mDiskCachePath = ImageFileUtils.getImageDownloadPath(mSubsamplingScaleImageView.getContext(), url);
                } else {
                    String fileName = ImageFileUtils.getFileName(url);
                    mDiskCachePath = mDiskCachePath + File.separator + fileName;
                }

                if (ImageFileUtils.exists(mDiskCachePath)) {
                    postImage();
                } else {
                    downloadImage(url);
                }
            } else {
                ImageLoader.loadImage(mSimpleDraweeView, uri, mWidth, mHeight, mPostprocessor,
                    mControllerListener, mSmallDiskCache);
            }
        }

        private void downloadImage(String url) {
            ImageLoader.downloadImage(mSubsamplingScaleImageView.getContext(), url, new IDownloadResult(mDiskCachePath) {
                @Override
                public void onProgress(final int progress) {
                    postProgressImage(progress);
                }

                @Override
                public void onResult(final String filePath) {
                    postResultImage(filePath, url);
                }
            });
        }

        private void postResultImage(String filePath, String url) {
            TaskDispatcher uiTaskDispatcher = mSubsamplingScaleImageView.getContext().getUITaskDispatcher();
            uiTaskDispatcher.asyncDispatch(new Runnable() {
                @Override
                public void run() {
                    if (filePath != null) {
                        PixelMap pixelmap = getPixelMap(filePath);
                        mSubsamplingScaleImageView.setPixelMap(pixelmap);
                    } else {
                        MLog.error("filePath = null url = " + url);
                    }
                }
            });
        }

        private void postProgressImage(int progress) {
            TaskDispatcher uiTaskDispatcher = mSubsamplingScaleImageView.getContext().getUITaskDispatcher();
            uiTaskDispatcher.asyncDispatch(new Runnable() {
                @Override
                public void run() {
                    mSubsamplingScaleImageView.onProgress(progress);
                }
            });
        }

        private void postImage() {
            TaskDispatcher uiTaskDispatcher = mSubsamplingScaleImageView.getContext().getUITaskDispatcher();
            uiTaskDispatcher.asyncDispatch(new Runnable() {
                @Override
                public void run() {
                    mSubsamplingScaleImageView.onProgress(100);
                    PixelMap pixelmap = getPixelMap(mDiskCachePath);
                    mSubsamplingScaleImageView.setPixelMap(pixelmap);
                }
            });
        }

        private PixelMap getPixelMap(String url) {
            ImageSource.SourceOptions sourceOptions = new ImageSource.SourceOptions();
            sourceOptions.formatHint = "image/png";
            ImageSource imageSource = ImageSource.create(url, sourceOptions);
            ImageSource.DecodingOptions decodingOptions = new ImageSource.DecodingOptions();
            decodingOptions.desiredSize = new Size(0, 0);
            decodingOptions.desiredRegion = new Rect(0, 0, 0, 0);
            decodingOptions.desiredPixelFormat = PixelFormat.ARGB_8888;
            PixelMap pixelmap = imageSource.createPixelmap(decodingOptions);
            return pixelmap;
        }

        private void loadBlur(String url) {
            Uri uri = Uri.parse(url);
            adjustLayoutParams();
            if (UriUtil.isNetworkUri(uri)) {
                ImageLoader.loadImageBlur(mSimpleDraweeView, url, mWidth, mHeight);
            } else {
                ImageLoader.loadFileBlur(mSimpleDraweeView, url, mWidth, mHeight);
            }
        }

        private void adjustLayoutParams() {
            if (mSimpleDraweeView == null) {
                return;
            }

            if (mWidth > 0 && mHeight > 0) {
                ComponentContainer.LayoutConfig lvp = mSimpleDraweeView.getLayoutConfig();
                lvp.width = mWidth;
                lvp.height = mHeight;
            } else if (mAspectRatio > 0 && (mWidth > 0 || mHeight > 0)) {
                ComponentContainer.LayoutConfig lvp = mSimpleDraweeView.getLayoutConfig();
                if (mWidth > 0) {
                    lvp.width = mWidth;
                    lvp.height = (int) (mWidth / mAspectRatio);
                } else {
                    lvp.height = mHeight;
                    lvp.width = (int) (mHeight * mAspectRatio);
                }
            }
        }
    }
}
